package demo4;

import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 姚东名
 * Date: 2024-06-08
 * Time: 17:32
 */
//4.数组练习
public class Test {
    //4.7数组逆序
    /*
    给定一个数组，将里面的元素逆序排序
    思路：
    设定两个下标，分别指向第一个元素和最后一个元素。交换两个位置的元素
    然后让前一个下标自增，后一个下标自减，循环继续即可
     */
    public static void reverse(int[] array) {
        int left = 0;
        int right = array.length - 1;
        while(left < right) {
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
            left++;
            right--;
        }
    }
    public static void main(String[] args) {
        int[] array = {5, 4, 3, 2, 1};
        System.out.println("逆序前的数组："+Arrays.toString(array));
        reverse(array);
        System.out.println("逆序后的数组："+Arrays.toString(array));
    }
    //4.6数组排序(冒泡排序)
    /*
    给定一个数组，让数组升序降序(降序)排序
    算法思路
    假设排升序：
     1.将数组相邻的元素从前往后依次进行比较，如前面一个元素大于后面一个元素，则交换，一趟下来后最大的元素就在数组末尾
     2.依次从上上述过程，知道数组所有元素都排序好
     */
    public static void bubbleSort(int[] array) {
        //i表示趟数
        for (int i = 0; i < array.length; i++) {
            boolean flag = false;
            //j表示一趟交换的次数
            for (int j = 0; j < array.length - 1 - i; j++) {
                //前面的大于后面的，就交换：
                if(array[j] > array[j + 1]) {
                    int tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;
                    flag = true;
                }
            }
            //假如flag没有发生变化，就说明j这一趟，没有进行排序 -> 证明已经是升序了
            if(flag == false) {
                return;
            }
        }
    }
    public static void main6(String[] args) {
        int[] array = {10, 8, 6, 9, 3};
        System.out.println("排序前的数组："+Arrays.toString(array));
        bubbleSort(array);//默认从小到大排序
        System.out.println("排序后的数组："+Arrays.toString(array));
    }
    //4.5查找数组中指定元素(二分查找)
    /*
    针对有序数组，可以使用更高效的二分查找
    什么叫有序数组？
    有序数组分为“升序”与“降序”
    如：1 2 3，依次递增的叫升序
    如：3 2 1，依次递减的叫降序

    以升序数组为例，二分查找的思路是先取中间位置的值，然后使用待查找的元素与数组中间元素进行对比：
    - 如果相等，即找到了返回该元素在数组中的下标
    - 如果小于，以类似方式到数组左半侧查找(mid = (right+left)/2)
    - 如果大于，以类似方式到数组右半侧查找(mid = (right+left)/2)
     */
    public static int binarySearch(int[] array, int key) {
        int left = 0;
        int right = array.length - 1;
        while(left < right) {
            //每循环一次，mid的值就会发生改变，所以定义在while{}里面
            int mid = (left + right) / 2;
            if(key < array[mid]) {
                //如果小于，以类似方式到数组左半侧查找:
                right = mid - 1;
            }
            if(key > array[mid]) {
                //如果大于，以类似方式到数组右半侧查找:
                left = key + 1;
            }
            if(key == array[mid]) {
                //相等就返回下标：
                return mid;
            }
        }
        //走到这，证明要找的值不存在了
        return -1;
    }
    public static void main5(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println(binarySearch(array, 5));
    }
    //4.4查找数组中指定元素(顺序查找) -> 本质上还是遍历数组
    public static int findArray(int[] array, int key) {
        for (int i = 0; i < array.length; i++) {
            if(key == array[i]) {
                return i;//返回下标
            }
        }
        //走到这，证明遍历完，还是没有找到数组中的key
        return -1;
    }
    public static void main4(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6};
        System.out.println(findArray(array, 2));
    }
    //4.3求数组中元素的平均值
    public static double avg(int[] array) {
        int sum = 0;
        //第一步：把数组中的元素加起来
        for(int x : array) {
            sum += x;
        }
        //第二步：总数除以长度 = 平均数
        return (double)sum / array.length;
    }
    public static void main3(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        System.out.println(avg(array));
    }
    //4.2数组拷贝
    public static void func() {
        /*
        newArray和array引用的是同一个数组
        因此newArray修改空间中的内容之后，array也可以看到修改的结果
         */
        int[] array = {1, 2, 3, 4, 5};
        int[] newArray = array;
        newArray[0] = 10;
        System.out.println("newArray："+Arrays.toString(array));

        /*
        使用Arrays中的copyOf方法完成数组的拷贝：
        copyOf方法在进行数组拷贝的时候，创建一个新的对数组了
        array和newArray引用的不是同一个数组了
         */
        array[0] = 1;
        newArray = Arrays.copyOf(array, array.length);
        System.out.println("newArray："+Arrays.toString(newArray));

        //因为array修改其引用数组的内容，并不会对newArray产生任何影响，
        //因为此时array和newArray引用的不是同一个数组了，修改一个引用的内容，不会影响另外一个引用的内容
        array[0] = 10;
        System.out.println("array："+Arrays.toString(array));
        System.out.println("newArray："+Arrays.toString(newArray));

        //拷贝某个范围
        int[] newArray2 = Arrays.copyOfRange(array, 2, 4);//[2, 4)
        System.out.println(Arrays.toString(newArray2));
    }

    //自己实现一个拷贝数组
    public static int[] copyOf(int[] array) {
        int[] ret = new int[array.length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = array[i];
        }
        return ret;
    }
    public static void main2(String[] args) {
        func();
        System.out.println("========================");
        int[] array = {1, 2, 3, 4, 5};
        System.out.println(Arrays.toString(copyOf(array)));
    }
    //4.1数组传字符串
    //代码展示
    public static void main1(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        String newArray = Arrays.toString(array);
        System.out.println(newArray);
    }
    //执行结果：
    //[1, 2, 3, 4, 5]
}
